#pragma once

#include <vector>
#include "PKB.h"


class DesignExtractor {

private:
	// ***********************
	// * Constructor Related *
	// ***********************
	PKB *pkb;
	static DesignExtractor* de;
	static bool isExist;

	// ***************
	// * Member Data *
	// ***************
	bool m_isBasicCompleted;
	vector<bool> m_isProcCompletedLastModified;
	vector<bool> m_isProcCompletedNextModified;
	Type::Map::LineMatrix m_lastModifiedTable;
	Type::Map::LineMatrix m_nextModifiedTable;
	vector<vector<Type::Index::Var>> m_confirmedVarsModifiedByProc;

	// ***********
	// * Utility *
	// ***********
	static vector<int> vectorUnion(vector<int> first, vector<int> second);
	static vector<int> vectorIntersect(vector<int> first, vector<int> second); 

	// *************
	// * Recursive *
	// *************
	int recurseAnalyseNext(Type::List::Line childList);
	int recurseAnalyseNextBip(Type::List::Line childList, Type::List::Line returnPoints);
	Type::List::Var recurseAnalyseLastModified(bool isProc, Type::List::Line childList, Type::List::Line lmTableEntry);
	Type::List::Var recurseAnalyseNextModified(bool isProc, Type::List::Line childList, Type::List::Line nmTableEntry); 

	// ***********
	// * Helpers *
	// ***********
	bool isCallersCompleted(Type::Index::Proc currentProc, vector<bool> isProcCompleted);
	bool isCompletedProc(Type::List::Proc subCalleeProcList, vector<bool> completedProcs);
	bool isProcCompleted(Type::Index::Proc proc, vector<bool> completedLinesCalls);

	void checkParentConditions(Type::Index::Line currentLine);
	void checkParentConditionsBip(Type::Index::Line currentLine, Type::List::Line returnPoints);
	void mergeBitmaps(Type::Map::Bit &lineUsesBitmap, Type::Map::Bit &lineModsBitmap);

	Type::Index::Line DesignExtractor::analyseParentList(Type::Index::Line currentLine);
	Type::List::Var getVarsOld(Type::Index::Proc currentProc, Type::Map::Bit bitmap);
	Type::List::Line updateTableEntry(Type::Index::Line currentLine, Type::List::Line lmTableEntry, Type::List::Var modifiedVars);

	// ***************
	// * Ryan's Part *
	// ***************
	void updateEarliestCommonParent(Type::Entity::Line);
	void updateParentMatrix(Type::Map::ParentMatrix&, Type::List::Line&, Type::Index::Line, 
		 Type::Entity::Line, Type::Index::Line);
	void updateParentMatrixOfContainer(Type::Map::ParentMatrix&, Type::List::Line&, 
		Type::Index::Line, Type::Entity::Line, Type::Index::Line&);
	void printParentMatrix(Type::Map::ParentMatrix&);

	
public:
	// ***********************
	// * Constructor Related *
	// ***********************
	/// Constructor for the DesignExtractor.
	DesignExtractor(PKB *origPKB);
	~DesignExtractor(void);
	static DesignExtractor* getInstance(void);


	// ***********
	// * Runners *
	// ***********
	///	Method to run the DesignExtractor based on the information in the PKB.
	int run();

	///	Method to run the DesignExtractor for extra features based on the information in the PKB.
	int runExtra();


	// **********************
	// * Individual Updates *
	// **********************
	/// Method to update the PKB on the status of which Procedure Uses/Modifies which Variable.
	int updateProcUMStatus(void);

	/// Method to update the PKB on the status of which Line Uses/Modifies which Variable.
	int updateLineUMStatus(void);

	/// Method to update the PKB on the status of Next(x, y) relationships.
	int updateNextStatus(void);

	/// Method to update all the Star relations in the PKB and store them for faster retrieval.
	int updateStarRelations(void);

	/// Method to update the PKB on the status of Next(x, y) relationships.
	int updateNextBipStatus(void);

	// **********
	// * Ryan's *
	// **********
	/// Method to update all Earliest Common Parent If and While
	int updateEarliestCommonParent();

	// ***********
	// * Yu De's *
	// ***********
	/// Sets the exit points of every procedure
	void setExitPointsOfProcs();
	/// Sets the exit point of one procedure
	void setExitPointOfProc(Type::Index::Proc proc);
	/// Sets updateNextBipStatus
	int updateNextBipStatus_Yude(void);


	// **************
	// * Data Fetch *
	// **************
	/// Method to get m_lastModifiedTable from DE
	Type::Map::LineMatrix getLastModifiedTable();
	Type::Map::LineMatrix getNextModifiedTable();
	void printLastNextTable(vector<vector<int>> table);
};